window.GlobalConstants = {
	// Treasure target height , assume the treasure is a square
	TREASURE_MAX_WIDTH : 105,
	// used to trigger a animation.
	ANIMATION_TRIGGER_ID : "animationTrigger",
	//
	CLONED_TREASURE_ID_SUFFIX : "-animation",
	//
	ANIMATIOIN_MASKER_ID : "animation-masker",
	//
	CANVAS_ROWS : 9,
	//
	CANVAS_COLS : 12
};
window.ALL_TREASURES = {};
window.ALL_LATTICES = {};

/**
 * Define a animation handler for centralize the animation handle.
 */
var AnimationHandler = {
	_playAnimation : function(treasure, animationArray) {
		var tre = treasure;
		if (animationArray == null || animationArray.length == 0) {
			return;
		}
		var animationDefine = animationArray.pop();
		// var animation = Animations[animationDefine.name];

		AnimationUtil.getTragger().delay(animationDefine.delay).animate({
			"height" : "0px"
		}, 0, function() {
			// setTimeout(function() {
			tre[animationDefine.name].play(tre);
			// });
			AnimationHandler._playAnimation(tre, animationArray);
		});
	},
	/**
	 * Fire the animation.
	 * 
	 * @param event
	 */
	fireAnimation : function(e) {
		var clas = e.target.className;
		var id = e.target.id;
		var treasure;
		if (clas == "treasure") {
			treasure = window.ALL_TREASURES[id];
		} else if (clas == "lattice") {
			treasure = window.ALL_LATTICES[id].treasure;
		}
		var arr = AnimationStack[treasure.attr("treasuretype")].slice().reverse();
		AnimationHandler._playAnimation(treasure, arr);
	}
};

/**
 * Setting the animation for each type of treasure.
 */
var AnimationStack = {
	// animate define for diamond type treasure
	diamond : [ {
		name : "hideLattice",
		delay : 0
	}, {
		name : "flickering",
		delay : 0
	}, {
		name : "progressivePop",
		delay : 0
	}, {
		name : "progressiveMinify",
		delay : 1000
	} ],

	// animate define for bomb type treasure
	bomb : [ {
		name : "hideLattice",
		delay : 0
	}, {
		name : "flickering",
		delay : 0
	}, {
		name : "progressivePop",
		delay : 0
	}, {
		name : "shocking",
		delay : 500
	}, {
		name : "explode",
		delay : 500
	} ]

};

/**
 * Util class . should integration with the other one.
 */
var Util = {
	getRandomPositionOutsideWindow : function() {
		var w = $(window).width(), h = $(window).height();
		var x = Math.round(Math.random() * 1000);
		var y = Math.round(Math.random() * 1000);
		var left = (x % 2 == 0) ? w + x : 0 - x;
		var top = (y % 2 == 0) ? h + y : 0 - y;
		return {
			"x" : left,
			"y" : top
		};
	}
};

/**
 * Canvas for treasure
 */
var Canvas = {
	innerWidth : 0,
	innerHeight : 0,
	margin : 10,
	layout : {
		"cols" : 0,
		"rows" : 0
	},
	/**
	 * Init the Canvas, will be invoked when document is ready:
	 * $(document).ready().
	 */
	init : function() {
		var cvs = $("#canvas");
		var offsetTop = cvs.offset().top;

		var width = $(window).width(), height = $(window).height() - offsetTop;
		this.innerWidth = width - this.margin * 2;
		this.innerHeight = height - this.margin * 2;

		this._initLayout();
		$.extend(true, this, cvs);

		cvs.animate({
			"width" : width + "px",
			"height" : height + "px"
		}, 150);
		return this;
	},
	/**
	 * The private method used to init the Canvas layout. Never call outside
	 * this class.
	 */
	_initLayout : function() {

		var colCount = 0, rowCount = 0;

		if (GlobalConstants.CANVAS_ROWS > 0 || GlobalConstants.CANVAS_COLS > 0) {
			colCount = GlobalConstants.CANVAS_COLS, rowCount = GlobalConstants.CANVAS_ROWS;	
		} else {
			var totalColumnMargin = this.innerWidth % LatticePrototype.width;
			var colCount = Math.floor(this.innerWidth / LatticePrototype.width);
			if (totalColumnMargin <= colCount) {
				totalColumnMargin = LatticePrototype.width;
				colCount--;
			}

			colMargin = Math.floor(totalColumnMargin / colCount);
			while (colMargin < 1) {
				colCount--;
				colMargin = Math.floor(totalColumnMargin / colCount);
			}

			var totalRowMargin = this.innerHeight % LatticePrototype.height;
			var rowCount = Math.floor(this.innerHeight / LatticePrototype.height);
			if (totalRowMargin <= rowCount) {
				totalRowMargin = LatticePrototype.height;
				rowCount--;
			}

			rowMargin = Math.floor(totalRowMargin / rowCount);
			while (rowMargin < 1) {
				rowCount--;
				rowMargin = Math.floor(totalRowMargin / rowCount);
			}

			LatticePrototype.marginX = colMargin;
			LatticePrototype.marginY = rowMargin;
		}
		this.layout = {
			'cols' : colCount,
			'rows' : rowCount
		};
	}
};

/**
 * Lattice prototype , used to create new instance.
 */
var LatticePrototype = {
	"class" : "lattice",
	"pos" : {
		x : 0,
		y : 0
	},
	"width" : 60,
	"height" : 60,
	"marginX" : 5,
	"marginY" : 5,
	"id" : "",
	"treasure" : {},
	/**
	 * Display this lattice with an animation.
	 */
	"display" : function() {
		this.animate({
			"left" : this["pos"].x + "px",
			"top" : this["pos"].y + "px"
		}, 1500);
	},
	/**
	 * Instance a lattice object.
	 */
	"instantiation" : function(attrs) {
		var initPos = Util.getRandomPositionOutsideWindow();
		$.extend(true, this, attrs);

		var lattice = $("<div/>");
		lattice.attr({
			"class" : this["class"],
			"id" : this.id
		}).css({
			"top" : initPos.y,
			"left" : initPos.x
		}).appendTo(Canvas);

		var obj = {};
		$.extend(true, obj, this, lattice);
		return obj;
	}
};

var TreasurePrototype = {
	"class" : "treasure",
	"pos" : {
		x : 0,
		y : 0
	},
	"height" : 50,
	"marginX" : 3,
	"marginY" : 3,
	"id" : "",
	"lattice" : {},
	"src" : "",
	"treasureType" : "",
	/**
	 * Display this lattice with an animation.
	 */
	"display" : function() {
		this.animate({
			"opacity" : 100
		}, 500);
	},
	/**
	 * Instance a lattice object.
	 */
	"instantiation" : function(attrs) {
		var treasure = $("<img/>");
		$.extend(true, this, attrs);
		treasure.css({
			"opacity" : 0
		});

		treasure.attr({
			"class" : this["class"],
			"src" : this.src,
			"id" : this.id,
			"treasureType" : this.treasureType
		}).appendTo(this.lattice);

		var obj = {};
		$.extend(true, obj, this, treasure);
		return obj;
	},

	clone4Animation : function() {

		var id = this.attr("id") + GlobalConstants.CLONED_TREASURE_ID_SUFFIX;
		var cloneObj = $("#" + id);
		if (cloneObj != null && cloneObj.length > 0) {
			return cloneObj;
		}

		var lattice = this.lattice;
		var clone = this.clone();

		var x = lattice.offset().left + "px", y = lattice.offset().top + "px";
		clone.attr({
			"id" : id,
			"class" : "treasureclone"
		}).css({
			"position" : "absolute",
			"height" : "0px",
			"top" : y,
			"left" : +x
		});
		clone.appendTo(lattice);
		return clone;
	},
};

var TreasureLoader = {
	load : function() {
		var treasures = this.create();
		$.each(treasures, function(index, treasure) {
			setTimeout(function() {
				treasure.display();
			}, Math.floor(Math.random() * 1500));
		});
	},
	create : function() {
		var treasures = [];
		var images = [ {
			"src" : "04.gif",
			"type" : "diamond"
		}, {
			"src" : "05.gif",
			"type" : "diamond"
		}, {
			"src" : "06.gif",
			"type" : "diamond"
		}, {
			"src" : "07.gif",
			"type" : "diamond"
		}, {
			"src" : "08.gif",
			"type" : "diamond"
		}, {
			"src" : "09.gif",
			"type" : "diamond"
		}, {
			"src" : "bomb2.jpg",
			"type" : "bomb"
		} ];
		var index = 0;
		for ( var key in window.ALL_LATTICES) {
			index++;
			var lattice = window.ALL_LATTICES[key];
			var i = Math.floor(Math.random() * 7);
			var src = images[i].src;
			var type = images[i].type;
			var tre = TreasurePrototype.instantiation({
				"id" : "treasure-" + index + 1,
				"src" : src,
				"lattice" : lattice,
				"treasureType" : type
			});
			lattice.treasure = tre;
			treasures.push(tre);
			window.ALL_TREASURES[tre.id] = tre;
		}
		return treasures;
	}
};

/**
 * Lattice loader , used to create lattices according the Canvas size. The
 * lattice number is dynamic counted according to the Canvas size.
 */
var LatticesLoader = {
	/**
	 * Load the lattices into Canvas.
	 */
	load : function() {
		var layout = Canvas.layout, n = 0, lattices = {};

		var canvasTop = Canvas.offset().top, canvasLeft = Canvas.offset().left;

		var latticeUnitWidth = LatticePrototype.width + LatticePrototype.marginX, latticeUnitHeight = LatticePrototype.height + LatticePrototype.marginY;
		var latticeInitLeft = canvasLeft + Canvas.margin, latticeInitTop = canvasTop + Canvas.margin;
		var previousLatticeLeft = latticeInitLeft, previousLatticeTop = latticeInitTop;

		for ( var i = 0; i < layout.rows; i++) {
			for ( var j = 0; j < layout.cols; j++) {
				n++;
				var l1 = LatticePrototype.instantiation({
					"pos" : {
						x : previousLatticeLeft,
						y : previousLatticeTop
					},
					"id" : "lattice-" + n
				});

				l1.bind("click", function(event) {
					AnimationHandler.fireAnimation(event);
				});
				lattices[l1.id] = l1;
				previousLatticeLeft += latticeUnitWidth;
			}
			previousLatticeLeft = latticeInitLeft;
			previousLatticeTop += latticeUnitHeight;
		}
		for ( var key in lattices) {
			lattices[key].display();
		}
		window.ALL_LATTICES = lattices;
		return lattices;
	}
}

/**
 * All animations definition. Copied from animations.js
 */
var Animations = {
	hideLattice : {
		"play" : function(target) {
			// var lattice = AnimationUtil.getLattice(e);
			// hide lattice
			target.css("background-color", "transparent");
			// unbind the click action .
			target.unbind("click");
		}
	},

	flickering : {
		"play" : function(target) {
			// the treasure object
			target.css("height", "50px");
			var i = 0, opct = 100;
			var pl = function() {
				if (i >= 5) {
					clearInterval(itv);
				} else {
					target.animate({
						"opacity" : opct
					}, 70);
					opct = opct == 100 ? 0 : 100;
					i++;
					itv = setInterval(pl, 71);
				}
			};
			var itv = setInterval(pl, 0);
		}
	},
	/**
	 * Play the animation when user click the masked treasure.
	 * 
	 * @param e
	 */
	progressivePop : {
		"play" : function(target) {
			// var pos = AnimationUtil.getAbsoluteCenterPosition(e);
			var pos = target.pos;
			var tc = target.clone4Animation();

			var fx = tc.offset().left, fy = tc.offset().top, tx = pos.x, ty = pos.y;
			var ox = "+=" + (tx - fx), oy = "+=" + (ty - fy);

			tc.css({
				"opacity" : 100,
				"position" : "absolute",
				"left" : fx + "px"
			}).animate({
				"height" : GlobalConstants.TREASURE_MAX_WIDTH + "px",
				"left" : ox,
				"top" : oy
			}, 150, "swing");
		}
	},

	/**
	 * progressive minify
	 * 
	 * @param e
	 */
	progressiveMinify : {
		"play" : function(target) {
			var clone = target.clone4Animation();
			// treasure animation
			clone.css({
				"position" : "absolute"
			}).animate({
				"height" : "0px",
				"opacity" : 0,
				"left" : $(window).width() + "px",
				"top" : "0px"
			}, 350);
		}
	},

	/**
	 * Transparency
	 */
	transparency : {
		"play" : function(target) {
			target.animate({
				"opacity" : 0
			}, 50);
		}
	},

	/**
	 * Shocking
	 * 
	 * @param e
	 */
	shocking : {
		"play" : function(target) {
			var treasure = target.clone4Animation();
			var shockMaxOffset = 4;

			var shockPosition = [ 'top', 'left' ], count = 0;
			shockIntervalObject = setInterval(function() {
				var randomPosition = shockPosition[count % 2];
				var shockOffset = (count++) % shockMaxOffset < 2 ? 0 : shockMaxOffset;
				var treasureCenterPosition = target.pos;
				if (randomPosition == 'top') {
					shockOffset += treasureCenterPosition.y;
				} else {
					shockOffset += treasureCenterPosition.x;
				}
				treasure.css(randomPosition, shockOffset);
				if (count > 35) {
					clearInterval(shockIntervalObject);
					count = 0;
				}
			}, 32);
		}
	},

	/**
	 * @param e
	 */
	explode : {
		"play" : function(target) {
			var pos = target.pos;
			var treasure = target.clone4Animation();

			treasure.animate({
				"opacity" : 0
			}, 200);

			var masker = AnimationUtil.createPageMasker();
			var bomb = $("<img/>");
			bomb.attr("src", "bomb4.jpg").css({
				"width" : "0px",
				"height" : "0px",
				"border" : "0",
				"z-index" : "101",
				"position" : "absolute",
				"top" : pos.y + "px",
				"left" : pos.x + "px"
			}).appendTo(masker);

			bomb.animate({
				"top" : "0px",
				"left" : "0px",
				"width" : $(window).width(),
				"height" : $(window).height()
			}, 80).animate({
				"top" : pos.y + "px",
				"left" : pos.x + "px",
				"width" : "0px",
				"height" : "0px",
				"opacity" : 0
			}, 120, function() {
				AnimationUtil.removeMasker();
			});

			// var bg = "#000", i = 5;
			// $("body").css({
			// "background-color" : "#fff"
			// }).animate({
			// "opacity" : "0"
			// }, 3000);
		}
	}
};

/**
 * Define a animation utility Class.
 */
var AnimationUtil = {
	initEnvironment : function() {
		var id = "#" + GlobalConstants.ANIMATION_TRIGGER_ID;
		var trigger = $(id);
		if (trigger == null || trigger == 'undefined' || trigger.length == 0) {
			$("<div/>").attr("id", GlobalConstants.ANIMATION_TRIGGER_ID).css({
				"width" : "0px",
				"height" : "0px",
				"visibility" : "hidden"
			}).appendTo($("body"));
		}
	},

	createPageMasker : function() {
		var w = $(window).width(), h = $(window).height();
		var marker = $("<div/>");

		marker.attr("id", GlobalConstants.ANIMATIOIN_MASKER_ID).css({
			"position" : "absolute",
			"top" : "0px",
			"left" : "0px",
			"z-index" : "100",
			"width" : w + "px",
			"height" : h + "px"
		}).appendTo($("body"));
		return marker;
	},

	removeMasker : function() {
		$("#" + Constants.ANIMATIOIN_MASKER_ID).remove();
	},

	removePageMasker : function() {
		$("#animation-masker").remove();
	},

	/**
	 * Get the absolute x,y coordinate consider the page scroll.
	 */
	getAbsoluteCenterPosition : function(e) {
		var lattice = AnimationUtil.getLattice(e);
		var x = ($(document).width() - lattice.width()) / 2;
		var y = $('html').scrollTop() + ($(window).height() - lattice.height()) / 2;
		return new Position(x, y);
	},
	/**
	 * Clone a new treasure for animation display. The original treasure keep in
	 * the place staticly.
	 */
	cloneAnimationTreasure : function(e) {
		var lattice = AnimationUtil.getLattice(e);
		var treasure = AnimationUtil.getTreasure(e);
		var clone = treasure.clone();

		var x = lattice.offset().left + "px", y = lattice.offset().top + "px";
		clone.attr("id", treasure.attr("id") + GlobalConstants.CLONED_TREASURE_ID_SUFFIX).removeAttr("class").css({
			"position" : "absolute",
			"height" : "0px",
			"top" : y,
			"left" : +x
		});
		clone.appendTo(lattice);
		return clone;
	},

	/**
	 * Get the treasure type.
	 */
	getTreasure : function(e) {
		var latticeId = "#" + e.target.id;
		// the treasure object
		return $(latticeId + " > img.treasure");
	},

	getTreasureClone : function(e) {
		var treasure = AnimationUtil.getTreasure(e);
		var tid = treasure.attr("id");
		return $("#" + tid + GlobalConstants.CLONED_TREASURE_ID_SUFFIX);
	},

	getLattice : function(e) {
		var latticeId = "#" + e.target.id;
		// the lattice jQuery object
		return $(latticeId);
	},

	getTragger : function() {
		var id = "#" + GlobalConstants.ANIMATION_TRIGGER_ID;
		var trigger = $(id);
		return trigger;
	}
};